package com.shire.shire_interface.common.utils;

import org.springframework.util.StringUtils;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * DateUtils.java
 * 日期时间工具
 */
public class DateUtil {

	/** 缺省日期格式 */
	public static final String DEFAULT_DATE_FMT = "yyyy-MM-dd";

	/** 缺省时间格式 */
	public static final String DEFAULT_TIME_FMT = "yyyy-MM-dd HH:mm:ss";

	/** 全部时区名字 */
	private static final List TimeZoneIds = Arrays.asList(TimeZone.getAvailableIDs());

	/** 自定义时区缓存 */
	private static final Map TimeZoneCache = new HashMap();
	
	/**北京时区*/
	public static final TimeZone timeZoneBeijing = TimeZone.getTimeZone("Asia/Shanghai");


	/**
	 * 转换日期毫秒数为缺省日期格式字符串
	 *
	 * @param date
	 * @return
	 */
	public static String Date2String(long date) {
		return Date2String(new Date(date), DEFAULT_DATE_FMT, null);
	}

	/**
	 * 转换日期毫秒数为缺省日期格式字符串
	 *
	 * @param date
	 * @param timeZone
	 * @return
	 */
	public static String Date2String(long date, TimeZone timeZone) {
		return Date2String(new Date(date), DEFAULT_DATE_FMT, timeZone);
	}

	/**
	 * 转换日期为缺省日期格式字符串
	 *
	 * @param date
	 * @return
	 */
	public static String Date2String(Date date) {
		return Date2String(date, DEFAULT_DATE_FMT, null);
	}

	/**
	 * 转换日期为缺省日期格式字符串
	 *
	 * @param date
	 * @param timeZone
	 * @return
	 */
	public static String Date2String(Date date, TimeZone timeZone) {
		return Date2String(date, DEFAULT_DATE_FMT, timeZone);
	}

	/**
	 * 转换日期毫秒数为缺省日期格式字符串
	 *
	 * @param date
	 * @return
	 */
	public static String Time2String(long date) {
		return Date2String(new Date(date), DEFAULT_TIME_FMT, null);
	}

	/**
	 * 转换日期毫秒数为缺省日期格式字符串
	 *
	 * @param date
	 * @param timeZone
	 * @return
	 */
	public static String Time2String(long date, TimeZone timeZone) {
		return Date2String(new Date(date), DEFAULT_TIME_FMT, timeZone);
	}

	/**
	 * 转换日期为缺省日期格式字符串
	 *
	 * @param date
	 * @return
	 */
	public static String Time2String(Date date) {
		return Date2String(date, DEFAULT_TIME_FMT, null);
	}

	/**
	 * 转换日期为缺省日期格式字符串
	 *
	 * @param date
	 * @param timeZone
	 * @return
	 */
	public static String Time2String(Date date, TimeZone timeZone) {
		return Date2String(date, DEFAULT_TIME_FMT, timeZone);
	}

	/**
	 * 转换日期为指定格式字符串
	 *
	 * @param date
	 * @param format
	 * @return
	 */
	public static String Date2String(Date date, String format) {
		return Date2String(date, format, null);

	}

	/**
	 * 转换日期为指定格式字符串
	 *
	 * @param date
	 * @param format
	 * @param timeZone
	 * @return
	 */
	public static String Date2String(Date date, String format, TimeZone timeZone) {
		if (date == null || format == null)
			return null;
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		if (timeZone != null)
			sdf.setTimeZone(timeZone);
		return sdf.format(date);

	}

	/**
	 * 解析日期时间字符串,支持 yyMMdd,yyyyMMdd, yyyy-MM-dd, yyyy/MM/dd, yyyyMMddHHmm,
	 * yyyyMMddHHmmss, yyyyMMddHHmmssSSS, yyyy-MM-dd HH:mm:ss, yyyy-MM-dd HH:mm:ss.SSS 格式,
	 * 其它方式结果不保证正确
	 *
	 * @param str
	 * @return date
	 */
	public static Date String2Date(String str) {
		return String2Date(str, (TimeZone) null);
	}

	/**
	 * 解析日期时间字符串,支持 yyMMdd,yyyyMMdd, yyyy-MM-dd, yyyy/MM/dd, yyyyMMddHHmm,
	 * yyyyMMddHHmmss, yyyyMMddHHmmssSSS, yyyy-MM-dd HH:mm:ss, yyyy-MM-dd HH:mm:ss.SSS, yyyyMMdd HH:mm:ss(add by zhongcf 20120220)格式,
	 * 其它方式结果不保证正确
	 *
	 * @param str
	 * @param timeZone
	 * @return date
	 */
	public static Date String2Date(String str, TimeZone timeZone) {
		if (str == null)
			return null;
		str = str.trim();
		if (str.length() == 6)
			return String2Date(str, "yyMMdd", timeZone);
		if (str.length() == 8)
			return String2Date(str, "yyyyMMdd", timeZone);
		if (str.length() == 10) {
			if (str.indexOf("-") != -1)
				return String2Date(str, "yyyy-MM-dd", timeZone);

			if (str.indexOf("/") != -1)
				return String2Date(str, "yyyy/MM/dd", timeZone);
		}
		if (str.length() == 12)
			return String2Date(str, "yyyyMMddHHmm", timeZone);
		if (str.length() == 14)
			return String2Date(str, "yyyyMMddHHmmss", timeZone);
		if (str.length() == 17)
			if(str.indexOf(":") != -1)
				return String2Date(str, "yyyyMMdd HH:mm:ss", timeZone);
			else
				return String2Date(str, "yyyyMMddHHmmssSSS", timeZone);
		if (str.length() == 19) {
			if (str.indexOf("-") != -1)
				return String2Date(str, "yyyy-MM-dd HH:mm:ss", timeZone);
			if (str.indexOf("/") != -1)
				return String2Date(str, "yyyy/MM/dd HH:mm:ss", timeZone);
		}
		if (str.length() == 23) {
			if (str.indexOf("-") != -1)
				return String2Date(str, "yyyy-MM-dd HH:mm:ss.SSS", timeZone);
			if (str.indexOf("/") != -1)
				return String2Date(str, "yyyy/MM/dd HH:mm:ss.SSS", timeZone);
		}
		try {
			return new SimpleDateFormat().parse(str);
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 按指定方式解析日期时间
	 *
	 * @param str
	 * @param format
	 * @return
	 */
	public static Date String2Date(String str, String format) {
		return String2Date(str, format, null);
	}

	/**
	 * 按指定方式解析日期时间
	 *
	 * @param str
	 * @param format
	 * @param timeZone
	 * @return
	 */
	public static Date String2Date(String str, String format, TimeZone timeZone) {
		if (str == null)
			return null;
		if (format == null)
			format = DEFAULT_DATE_FMT;
		SimpleDateFormat fmt = new SimpleDateFormat(format);
		if (timeZone != null)
			fmt.setTimeZone(timeZone);
		try {
			return fmt.parse(str);
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 比较两个日期是否是一天(不考虑时间)
	 *
	 * @param date1
	 * @param date2
	 * @return
	 */
	public static boolean isDateEqual(Date date1, Date date2) {
		return truncDate(date1).equals(truncDate(date2));
	}

	/**
	 * 比较两个日期是否是一天(不考虑时间)
	 *
	 * @param date1
	 * @param date2
	 * @param timeZone
	 * @return
	 */
	public static boolean isDateEqual(Date date1, Date date2, TimeZone timeZone) {
		return truncDate(date1, timeZone).equals(truncDate(date2, timeZone));
	}

	/**
	 * 返回某日零时整
	 *
	 * @param date
	 * @return
	 */
	public static Date truncDate(Date date) {
		return truncDate(date, Calendar.DATE);
	}

	/**
	 * 返回某日零时整
	 *
	 * @param date
	 * @param timeZone
	 * @return
	 */
	public static Date truncDate(Date date, TimeZone timeZone) {
		return truncDate(date, Calendar.DATE, timeZone);
	}

	/**
	 * 日期时间取整，支持年、月、周、日、时、分、秒
	 *
	 * @param date
	 * @param mode
	 * @return date
	 */
	public static Date truncDate(Date date, int mode) {
		return truncDate(date, mode, null);
	}

	/**
	 * 日期时间取整，支持年、月、周、日、时、分、秒
	 *
	 * @param date
	 * @param mode
	 * @param timeZone
	 * @return date
	 */
	public static Date truncDate(Date date, int mode, TimeZone timeZone) {
		if (date == null)
			return null;
		Calendar cal = (timeZone == null ? Calendar.getInstance() : Calendar.getInstance(timeZone));
		cal.setTime(date);
		switch (mode) {
		case Calendar.YEAR:
			cal.clear(Calendar.MONTH);
		case Calendar.MONTH:
		case Calendar.WEEK_OF_MONTH:
			if (mode == Calendar.MONTH)
				cal.set(Calendar.DAY_OF_MONTH, 1);
			else
				cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
		case Calendar.DATE:
			cal.set(Calendar.HOUR_OF_DAY, 0);
		case Calendar.HOUR:
			cal.clear(Calendar.MINUTE);
		case Calendar.MINUTE:
			cal.clear(Calendar.SECOND);
		case Calendar.SECOND:
			cal.clear(Calendar.MILLISECOND);
			break;
		default:
			throw new IllegalArgumentException();
		}
		return cal.getTime();
	}

	/**
	 * 循环调整时间
	 *
	 * @param date
	 * @param field
	 * @param amount
	 * @return
	 */
	public static Date rollDate(Date date, int field, int amount) {
		return rollDate(date, field, amount, null);
	}

	/**
	 * 循环调整时间
	 *
	 * @param date
	 * @param field:1年份,2月份,3周,5天
	 * @param amount 加减值
	 * @param timeZone
	 * @return
	 */
	public static Date rollDate(Date date, int field, int amount, TimeZone timeZone) {
		Calendar cal = (timeZone == null ? Calendar.getInstance() : Calendar.getInstance(timeZone));
		cal.setTime(date);
		cal.roll(field, amount);
		return cal.getTime();
	}

	/**
	 * 调整时间
	 *
	 * @param date
	 * @param field
	 * @param amount
	 * @return
	 */
	public static Date addDate(Date date, int field, int amount) {
		return addDate(date, field, amount, null);
	}

	/**
	 * 调整时间
	 *
	 * @param date
	 * @param field
	 * @param amount
	 * @param timeZone
	 * @return
	 */
	public static Date addDate(Date date, int field, int amount, TimeZone timeZone) {
		Calendar cal = (timeZone == null ? Calendar.getInstance() : Calendar.getInstance(timeZone));
		cal.setTime(date);
		cal.add(field, amount);
		return cal.getTime();
	}
	/**
	 * 调整小时
	 * @param date
	 * @param hour
	 * @return
	 */
	public static Date addHours(Date date, int hour) {
		return addDate(date,Calendar.HOUR,hour);
	}
	/**
	 * 比较2个同时区时间先后，注意:时间的格式必须在String2Date支持的格式范围内
	 *
	 * @param date1 时间1
	 * @param date2 时间2
	 * @return 如果时间1等于时间2，返回0，如果时间1小于时间2，返回负值，如果时间1大于时间2，返回正值
	 */
	public static int compare(String date1, String date2) {
		return String2Date(date1).compareTo(String2Date(date2));
	}

	/**
	 * 比较2个时间先后
	 *
	 * @param date1 时间1
	 * @param date2 时间2
	 * @return 如果时间1等于时间2，返回0，如果时间1小于时间2，返回负值，如果时间1大于时间2，返回正值
	 */
	public static int compare(Date date1, Date date2) {
		return date1.compareTo(date2);
	}

	/**
	 * 查询时区
	 *
	 * @param timediff
	 * @return
	 */
	public static TimeZone findTimeZone(int timediff) {
		String[] ids = TimeZone.getAvailableIDs(timediff * 60000 + TimeZone.getDefault().getOffset(System.currentTimeMillis()));
		if (ids == null)
			return new SimpleTimeZone(timediff * 60000, "UDT");
		return TimeZone.getTimeZone(ids[0]);
	}

	/**
	 * 根据时区名字取得时区
	 * 如果非java已知标准名字，则必须为 GMT[+-]hh:mm 格式
	 * @param id
	 */
	public static TimeZone getTimeZone(String id) {
		if (id == null)
			return null;
		if (TimeZoneIds.contains(id))
			return TimeZone.getTimeZone(id);
		if (TimeZoneCache.containsKey(id))
			return (TimeZone) TimeZoneCache.get(id);
		Pattern p = Pattern.compile("^GMT[+-](0[0-9]|1[01]):([0-5][0-9])$");
		Matcher m = p.matcher("id");
		if (!m.matches())
			return null;
		int hh = Integer.parseInt(id.substring(4, 6));
		int mm = Integer.parseInt(id.substring(7));
		int sign = (id.charAt(3) == '-' ? -1 : 1);
		TimeZone tz = new SimpleTimeZone((hh * 60 + mm) * 60000 * sign, id);
		TimeZoneCache.put(id, tz);
		return tz;
	}

	public static Timestamp string2TimeStamp(Object millions, Object nanos) {
		try {
			Timestamp res = new Timestamp(Long.parseLong((String) millions));
			res.setNanos(Integer.parseInt((String) nanos));

			return res;
		} catch (Exception e) {
			return null;
		}

	}

	/** 把Date转为Timestamp */
	public static Timestamp date2Timestamp(Date adate) {
		return new Timestamp(adate.getTime());
	}

	/**
	 * <p>
	 * 把用户当地时间转成网银时间。
	 * </p>
	 *
	 * @param date 待转换的时间。
	 * @param dest 用户所在时区。
	 * @return 转换后的时间。
	 */
	public static Date transformDateFrom(Date date, TimeZone dest) {

//		long offset = dest.getOffset(date.getTime()) - timeZoneBeijing.getOffset(date.getTime());
//		Calendar cal = Calendar.getInstance();
//		cal.setTimeInMillis(date.getTime() - offset);
//		return cal.getTime();
		return transformDate(date, dest, timeZoneBeijing);
	}

	/**
	 * <p>
	 * 把网银时间转成用户当地时间。
	 * </p>
	 *
	 * @param date 待转换的时间。
	 * @param dest 用户所在时区。
	 * @return 转换后的时间。
	 */
	public static Date transformDateInto(Date date, TimeZone dest) {
//		long offset = dest.getOffset(date.getTime()) - timeZoneBeijing.getOffset(date.getTime());
//		Calendar cal = Calendar.getInstance();
//		cal.setTimeInMillis(date.getTime() + offset);
//		return cal.getTime();
		return transformDate(date, timeZoneBeijing, dest);
	}
	
	private static Date transformDate(Date dateSrc, TimeZone src, TimeZone dest) {
		Calendar cal = Calendar.getInstance(dest);
		cal.setTimeInMillis(dateSrc.getTime());
		int yy = cal.get(Calendar.YEAR);
		int MM = cal.get(Calendar.MONTH);
		int dd = cal.get(Calendar.DATE);
		int HH = cal.get(Calendar.HOUR_OF_DAY);
		int mm = cal.get(Calendar.MINUTE);
		int ss = cal.get(Calendar.SECOND);
		int sss = cal.get(Calendar.MILLISECOND);
		Calendar calBJ = Calendar.getInstance(src);
		calBJ.set(Calendar.YEAR, yy);
		calBJ.set(Calendar.MONTH, MM);
		calBJ.set(Calendar.DATE, dd);
		calBJ.set(Calendar.HOUR_OF_DAY, HH);
		calBJ.set(Calendar.MINUTE, mm);
		calBJ.set(Calendar.SECOND, ss);
		calBJ.set(Calendar.MILLISECOND, sss);
		return calBJ.getTime();
	}

	/**
	 * 校验起始日期和结束日期的合法性<p>
	 * 例如：起始日期距当前日期不超过12个月，起始结束日期间隔不超过3个月，调用<br>
	 * validateDateRange(startDate, endDate, currentDate, 3, 12)
	 * 
	 * @param startDate 起始日期
	 * @param endDate   结束日期
	 * @param currentDate 当前日期
	 * @param maxInterval 起始日期和结束日期的最大距离（单位为月）
	 * @param amount      起始日期和当前日期的最大距离（单位为月）
	 * @return
	 */
	public static boolean validateDateRange(Date startDate, Date endDate, Date currentDate, int maxInterval, int amount) {
		if (startDate.after(endDate))
			return false;

		if (currentDate.after(addDate(startDate, Calendar.MONTH, amount)))
			return false;

		if (endDate.after(addDate(startDate, Calendar.MONTH, maxInterval)))
			return false;

		return true;
	}
	
	  /**  
     * 计算两个日期之间相差的天数  
     * @param smdate 较小的时间 
     * @param bdate  较大的时间 
     * @return 相差天数 
     * @throws ParseException  
     */    
    public static int daysBetween(Date smdate,Date bdate) throws ParseException    
    {    
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); 
        //日期取整，去掉小时分钟秒
        smdate=sdf.parse(sdf.format(smdate));  
        bdate=sdf.parse(sdf.format(bdate));  
        Calendar cal = Calendar.getInstance();    
        cal.setTime(smdate);    
        long time1 = cal.getTimeInMillis();                 
        cal.setTime(bdate); 
        long time2 = cal.getTimeInMillis();         
        long between_days=(time2-time1)/(1000*3600*24);  
            
       return Integer.parseInt(String.valueOf(between_days));           
    }    
      

    /**
     * 字符串的日期格式的计算
     * @param smdate 较小的时间 
     * @param bdate  较大的时间 
     * @return 相差天数 
     * @throws ParseException
     */
    public static int daysBetween(String startdate,String enddate) throws ParseException{ 
    	
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        Date smdate=String2Date(startdate);
        Date bdate=String2Date(enddate);
        //日期取整，去掉小时分钟秒
        smdate=sdf.parse(sdf.format(smdate));  
        bdate=sdf.parse(sdf.format(bdate));  
        
        Calendar cal = Calendar.getInstance();    
        cal.setTime(smdate);    
        long time1 = cal.getTimeInMillis();                 
        cal.setTime(bdate);
        long time2 = cal.getTimeInMillis();         
        long between_days=(time2-time1)/(1000*3600*24);  
            
       return Integer.parseInt(String.valueOf(between_days));     
    } 
	/**
	 * 取得指定日期是星期几
	 * @param date
	 * @return 1:星期日,2:星期一,3:星期二,4:星期三,5:星期四,6:星期五,7:星期六
	 */
    public static int getWeek(Date date){  
        String[] weeks = {"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};  
        Calendar cal = Calendar.getInstance();  
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_WEEK);  
    } 
    /** 
     *  
     * @param year 
     *            int 年份 
     * @param month 从0开始
     *            int 月份 
     *  
     * @return int 某年某月的最后一天 
     */  
    public static int getLastDayOfMonth(int year, int month) {  
        Calendar cal = Calendar.getInstance();  
        cal.set(Calendar.YEAR, year);  
        cal.set(Calendar.MONTH, month);  
        // 某年某月的最后一天  
        return cal.getActualMaximum(Calendar.DATE);  
    }
 
    /** 
     *  
     * @param year 
     *            String 年份 
     * @param month 从0开始
     *            String 月份 
     *  
     * @return int 某年某月的最后一天 
     */  
    public static int getLastDayOfMonth(String year, String month) { 
    	if(StringUtils.isEmpty(year)|| StringUtils.isEmpty(month))return -1;
        Calendar cal = Calendar.getInstance();  
        cal.set(Calendar.YEAR, Integer.parseInt(year));  
        cal.set(Calendar.MONTH, Integer.parseInt(month)-1);  
        // 某年某月的最后一天  
        return cal.getActualMaximum(Calendar.DATE);  
    }
    /**
     * 得到上个月
     * @param date
     * @return
     */
    
    public static Date getBeforeMonth(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, -1);
        return cal.getTime();
    }
    /**
     * 得到上几个月
     * @param date
     * @return
     */
    
    public static Date getBeforeMonth(Date date,int count) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, count);
        return cal.getTime();
    }
    
    /**
     * 得到上几个月
     * @param date
     * @return
     */
    
    public static Date getCulDate(Date date,int count) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, count);
        return cal.getTime();
    }
    /**
     * 得到前一个月
     * @param String[]
     * @return
     */
    
    public static String[] getBeforeMonth(String year,String month) {
    	if(StringUtils.isEmpty(year)|| StringUtils.isEmpty(month))return null;
    	String cal_ym[]=new String[2];
        Calendar cal = Calendar.getInstance();
        //月份是从0开始的
        cal.set(Integer.parseInt(year), Integer.parseInt(month)-1, 1,0,0,1);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(sdf.format(cal.getTime()));
        //cal.set(Calendar.YEAR, Integer.parseInt(year));  
        //cal.set(Calendar.MONTH, Integer.parseInt(month));  
        cal.add(Calendar.MONTH, -1);
        cal_ym[0]=Integer.toString(cal.get(Calendar.YEAR));
        if(cal.get(Calendar.MONTH)+1<10){
        	cal_ym[1]="0"+Integer.toString(cal.get(Calendar.MONTH)+1);
        }else{
        	cal_ym[1]=Integer.toString(cal.get(Calendar.MONTH)+1);
        }
        
        System.out.println(sdf.format(cal.getTime()));
        return cal_ym;
    }
    /**
     * 得到前一个月
     * @param String[]
     * @return
     */
    
    public static String[] getBeforeMonth(int year,int month) {
    	String cal_ym[]=new String[2];
        Calendar cal = Calendar.getInstance();
        cal.set(year, month-1, 1);
        cal.add(Calendar.MONTH, -1);
        cal_ym[0]=Integer.toString(cal.get(Calendar.YEAR));
        cal_ym[1]=Integer.toString(cal.get(Calendar.MONTH)+1);
        return cal_ym;
    }
	/**
	 * 通过年月，取得当月的天数
	 * @param year
	 * @param month
	 * @return
	 */
	public static int getdaysByYM(String year,String month)
	{
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.YEAR, Integer.parseInt(year));
		calendar.set(Calendar.DATE, 1);
		calendar.set(Calendar.MONTH, Integer.parseInt(month) -1);
		int maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        return maxDay;

	}
	public static String getDate(){
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

		return dateFormat.format(new Date());
	}

	public static void main(String[] args) {
		String[] date1=getBeforeMonth("2017","04");
		System.out.println(date1[0]+":::"+date1[1]);
		System.out.println(getdaysByYM("2017","04"));
		date1=getBeforeMonth("2017","02");
		System.out.println(date1[0]+":::"+date1[1]);
		System.out.println(getdaysByYM("2017","02"));
	}
}